package com.immortal.core.module.log.aop;

import com.immortal.core.module.log.annotation.Log;
import com.immortal.core.module.log.handlers.LogHandler;
import com.immortal.core.module.log.handlers.LogHandlerHelp;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.util.StringUtils;

/**
 * <p>Title: LogAspect</p>
 * <p>Description: TODO</p>
 *
 * @author xukk
 * @version 1.0
 * @date 2018/6/8
 */
@Aspect
@Slf4j
public class LogAspect {
    @Before("@annotation(beforeLog) && @annotation(com.immortal.core.module.log.annotation.LogBefore)")
    public void doBefore(JoinPoint joinPoint, Log beforeLog) {
        if (StringUtils.isEmpty(beforeLog.condition())||(StringUtils.hasText(beforeLog.condition())
                && LogHandlerHelp.isConditionPassing(joinPoint, beforeLog.condition()))) {
            try {
                ((LogHandler) beforeLog.fallback().newInstance()).handlerBefore(beforeLog, joinPoint);
            } catch (Exception e){
                log.warn("handlerBefore:"+e.getMessage());
            }
        }
    }

    @After("@annotation(afterLog) && @annotation(com.immortal.core.module.log.annotation.LogAfter)")
    public void doAfter(JoinPoint joinPoint, Log afterLog) {
        if (StringUtils.isEmpty(afterLog.condition())||(StringUtils.hasText(afterLog.condition())
                && LogHandlerHelp.isConditionPassing(joinPoint, afterLog.condition()))) {
            try {
                ((LogHandler) afterLog.fallback().newInstance()).handlerAfter(afterLog, joinPoint, null);
            }  catch (Exception e){
                log.warn("handlerAfter:"+e.getMessage());
            }
        }
    }

    @AfterReturning(pointcut = "@annotation(afterReturningLog)  " +
            "&& @annotation(com.immortal.core.module.log.annotation.LogAfterReturing)",
            returning = "returnVal")
    public void afterReturn(JoinPoint joinPoint, Log afterReturningLog, Object returnVal) {
        if (StringUtils.isEmpty(afterReturningLog.condition())||(StringUtils.hasText(afterReturningLog.condition())
                && LogHandlerHelp.isConditionPassing(joinPoint, afterReturningLog.condition()))) {
            try {
                ((LogHandler) afterReturningLog.fallback().newInstance()).handlerAfterReturning(afterReturningLog, joinPoint, returnVal);
            }  catch (Exception e){
                log.warn("handlerAfterReturning:"+e.getMessage());
            }
        }
    }

    @AfterThrowing(pointcut = "@annotation(afterThrowingLog) " +
            " && @annotation(com.immortal.core.module.log.annotation.LogAfterThrowing)", throwing = "error")
    public void afterThrowing(JoinPoint joinPoint, Log afterThrowingLog, Throwable error) {
        if (StringUtils.isEmpty(afterThrowingLog.condition())
                ||(StringUtils.hasText(afterThrowingLog.condition())
                && LogHandlerHelp.isConditionPassing(joinPoint, afterThrowingLog.condition()))) {
            try {
                ((LogHandler) afterThrowingLog.fallback().newInstance()).handlerAfterThrowing(afterThrowingLog, joinPoint, error);
            } catch (Exception e){
                log.warn("error:"+e.getMessage());
            }
        }
    }

    @Around("@annotation(aroundLog) && @annotation(com.immortal.core.module.log.annotation.LogAround)")
    public Object around(ProceedingJoinPoint pjp, Log aroundLog) throws Throwable {
        if (StringUtils.isEmpty(aroundLog.condition())
                ||(StringUtils.hasText(aroundLog.condition())
                && LogHandlerHelp.isConditionPassing(pjp, aroundLog.condition()))) {
            try {
                ((LogHandler) aroundLog.fallback().newInstance()).handlerBefore(aroundLog, pjp);
            } catch (Exception e) {
                log.warn("handlerBefore:"+e.getMessage());
            }
        }
        Object o = null;
        try {
            o = pjp.proceed();
        } finally {
            if (StringUtils.isEmpty(aroundLog.condition())
                    ||(StringUtils.hasText(aroundLog.condition())
                    && LogHandlerHelp.isConditionPassing(pjp, aroundLog.condition()))) {
                try {
                    ((LogHandler) aroundLog.fallback().newInstance()).handlerAfter(aroundLog, pjp, o);
                } catch (Exception e) {
                    log.warn("handlerAfter:"+e.getMessage());
                }
            }

        }
        return o;
    }

}
